package com.iflytek.uoamp.notify.core.adapter;

import com.iflytek.uoamp.common.notify.constant.ConstField;
import com.iflytek.uoamp.common.notify.enumerate.ContactState;
import com.iflytek.uoamp.common.notify.exception.NotifyException;
import com.iflytek.uoamp.common.notify.obj.Contact;
import com.iflytek.uoamp.common.notify.obj.Notification;
import com.iflytek.uoamp.common.notify.plugins.AbstractPlugin;
import com.iflytek.uoamp.common.notify.util.LogbackInstance;
import com.iflytek.uoamp.notify.core.dump.DumpTask;
import com.iflytek.uoamp.notify.core.protocol.DumpInfo;
import com.iflytek.uoamp.notify.core.protocol.NotificationContent;
import org.slf4j.Logger;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

public class NotifyTask implements Runnable {

    private Queue<NotificationContent> queue = null;

    private static final int MAX_SIZE = 65535;

    private static final Logger logger = LogbackInstance.getInstance().getLogger(NotifyTask.class);

    private static class InstanceHolder {
        private static final NotifyTask instance = new NotifyTask();
    }

    private NotifyTask() {
        queue = new LinkedBlockingQueue<NotificationContent>(MAX_SIZE);
    }
    
    public static final NotifyTask getInstance() {
        return InstanceHolder.instance;
    }
    
    @Override
    public void run() {
        while(true) {
            if (!queue.isEmpty()) {
                try {
                    NotificationContent nc = queue.poll();
                    //执行任务
                    doTask(nc);
                } catch(Exception e) {
                    logger.error(MessageFormat.format(ConstField.UNKNOWNERROR, e.getMessage()), e);
                }
            } else {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 把通知信息放入队列
     * @param notificationContent
     * @throws NotifyException
     */
    public void addTask(NotificationContent notificationContent) throws NotifyException{
        if(queue.offer(notificationContent) == false) {
            logger.error(MessageFormat.format(ConstField.QUEUEISFULL, notificationContent.getNotificationDesc()));
            // ltzeng 如果通知加入队列失败，则写入dump文件，由Dump定时任务重新发送
            Notification notification = notificationContent.getNotification();
            DumpTask.dumpAll(notification);
        }
    }

    private void doTask(NotificationContent nc){
        AbstractPlugin plugin = nc.getPlugin();
        String text = nc.getText();
        List<Contact> contacts = nc.getContacts();
        if(!plugin.sendContent(text, contacts)) {
            // ltzeng 发送失败，将通知写入dump文件中，等待dump定时任务重新发送
            writeDumpFile(contacts, text, nc.getPluginType());
        }
    }

    private void writeDumpFile(List<Contact> contacts, String content,
                               String pluginType) {
        List<Contact> failedContacts = getFailedContacts(contacts);

        if(!failedContacts.isEmpty()) {
            DumpInfo dumpInfo = new DumpInfo(failedContacts, content, pluginType);
            DumpTask.writeToFile(dumpInfo);
        }
    }

    private List<Contact> getFailedContacts(List<Contact> contacts) {
        List<Contact> failed = new ArrayList<Contact>();
        for(Contact contact : contacts) {
            if(contact.getState() == ContactState.FAILED) {
                failed.add(contact);
            }
            contact.setState(ContactState.UNKNOWN);
        }

        return failed;
    }

}
